package sysApi

import (
	"bytes"
	"fmt"
	"gitee.com/jokces/kit/errc"
	"gitee.com/jokces/kit/ginutil"
	"gitee.com/jokces/kit/global"
	sysModel "gitee.com/jokces/kit/global/admin/model"
	"gitee.com/jokces/kit/global/admin/token"
	"github.com/gin-gonic/gin"
	"io"
	"net/http"
	"time"
)

// RegisterAdminRouter 注册路由的处理
func (r *AdminRouter) RegisterAdminRouter(e *gin.Engine) {

	//部门相关
	dep := e.Group("/admin/v1/dep").Use(r.VerifyLogin())
	{
		dep.GET("/treeList", r.depTreeList)
		dep.POST("/add", r.depAdd)
		dep.POST("/edit", r.depEdit)
		dep.POST("/del", r.depDel)
	}

	//菜单
	menu := e.Group("/admin/v1/menu").Use(r.VerifyLogin())
	{
		menu.GET("/treeList", r.menuTreeList)
		menu.POST("/add", r.menuAdd)
		menu.POST("/edit", r.menuEdit)
		menu.POST("/del", r.menuDel)
	}

	//资源
	action := e.Group("/admin/v1/action").Use(r.VerifyLogin())
	{
		action.GET("/list", r.actionList)
		action.POST("/edit", r.actionEdit)
		action.POST("/doc", r.actionAddDoc)
		action.POST("/del", r.actionDel)
	}

	//菜单对应的功能列表
	bind := e.Group("/admin/v1/bind").Use(r.VerifyLogin())
	{
		bind.GET("/menuAction", r.menuActions)
		bind.POST("/menuAction", r.bindActions)
	}

	//角色
	role := e.Group("/admin/v1/role").Use(r.VerifyLogin())
	{
		role.GET("/list", r.roleList)
		role.POST("/add", r.roleAdd)
		role.POST("/edit", r.roleEdit)
		role.POST("/del", r.roleDel)
		role.GET("/permission", r.rolePermission)
		role.POST("/bindActions", r.roleBindAction)
		role.GET("/dataList", r.roleDataList)
	}

	//用户相关接口
	user := e.Group("/admin/v1/user").Use(r.VerifyLogin())
	{
		user.GET("/list", r.userList)
		user.POST("/add", r.userAdd)
		user.POST("/edit", r.userEdit)
		user.POST("/disabled", r.disabledUser)
		user.POST("/pass", r.userRestPass)
		user.POST("/myPass", r.userRestMyPass) //用户修改自己的密码
		user.POST("/modify", r.userRestMyInfo) //用户修改自己的信息
		user.GET("/info", r.userInfo)
		user.GET("/menus", r.userMenu)
	}

	sys := e.Group("/admin/v1").Use(r.VerifyLogin())
	{
		//系统配置相读取
		sys.GET("/param/list", r.paramList)
		sys.POST("/param/edit", r.paramEdit)
		sys.GET("/opt/list", r.optAdminList)
		sys.GET("/dict/list", r.dictList)
	}

	tokenApi := e.Group("/admin/v1/token").Use(r.VerifyLogin())
	{
		tokenApi.GET("/account", r.tokenAccountList)
		tokenApi.GET("/user", r.tokenUserList)
	}

	client := e.Group("/admin/v1/client").Use(r.VerifyLogin())
	{
		client.GET("/list", r.clientList)
		client.POST("/add", r.clientAdd)
		client.POST("/edit", r.clientEdit)
		client.POST("/del", r.clientDel)
		client.POST("/resource", r.clientResource)
	}

	cly := e.Group("/admin/v1/classify").Use(r.VerifyLogin())
	{
		cly.GET("/list", r.classifyList)
		cly.POST("/add", r.classifyAdd)
		cly.POST("/edit", r.classifyEdit)
		cly.POST("/del", r.classifyEdit)
	}

}

// RegisterBaseRouter 公共的接口处理
func (r *AdminRouter) RegisterBaseRouter(e *gin.Engine) {

	//配置图片的现实,需要处理
	if global.GetCfg().Oss.LocalConf.Enable && global.GetCfg().Oss.LocalConf.FilePath != "" {
		e.StaticFS(global.GetCfg().Oss.LocalConf.FilePath, http.Dir(global.GetCfg().Oss.LocalConf.FilePath))
	}

	//图片上传
	file := e.Group("/:appType/file").Use(r.VerifyToken())
	{
		file.POST("/upload", r.uploadFile)
	}

	//授权的处理
	oauth := e.Group("/:appType/oauth")
	{
		oauth.GET("/token", r.accessToken)
		oauth.POST("/token", r.accessToken) //登录处理
		oauth.GET("/check", r.checkToken)
		//验证码
		oauth.GET("/captcha", r.captchaCode)

		//退出登录
		oauth.POST("/out", r.loginOut).Use(r.VerifyToken())
	}

	//短信验证码
	msg := e.Group("/:appType/msg")
	{
		msg.POST("/send", r.smsSend)
		msg.POST("/check", r.smsCheck)
		msg.POST("/token/send", r.smsSendWithToken).Use(r.VerifyToken())
	}

	//邮件
	email := e.Group("/:appType/email")
	{
		email.POST("/send", r.sendEmail)
		email.POST("/check", r.checkEmail)
		email.POST("/token/send", r.emailSendWithToken).Use(r.VerifyToken())
	}

	//基础字典相关的数据接口
	area := e.Group("/:appType/area")
	area.GET("/list", r.areaList).Use(r.VerifyToken())

	dic := e.Group("/:appType/dic")
	dic.GET("/list", r.dicList).Use(r.VerifyToken())
}

// VerifyToken 检验token是否存在的处理
func (r *AdminRouter) VerifyToken() gin.HandlerFunc {
	return func(c *gin.Context) {
		accessToken := c.GetHeader(sysModel.TokenHeader)
		if len(accessToken) <= 0 {
			ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s not found", sysModel.TokenHeader)))
			c.Abort()
			return
		}
		t, err := r.s.AccessToken(accessToken)
		if err != nil {
			ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
			c.Abort()
			return
		}

		if t.Typ == 1 {
			user, err := r.s.AdminSessionUser(t, accessToken)
			if err != nil {
				ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
				c.Abort()
				return
			}
			if user.Id <= 0 {
				ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", "login out")))
				c.Abort()
				return
			}
			c.Set(sysModel.TokenHeader, user)
		} else {
			user, err := r.s.ApiSessionUser(t, accessToken)

			if err != nil {
				ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
				c.Abort()
				return
			}
			if user.Id <= 0 {
				ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", "login out")))
				c.Abort()
				return
			}
			c.Set(sysModel.TokenHeader, user)
		}

		c.Next()
	}
}

// VerifyLogin 需要验证登录，验证权限的处理
func (r *AdminRouter) VerifyLogin() gin.HandlerFunc {
	return func(c *gin.Context) {
		accessToken := c.GetHeader(sysModel.TokenHeader)
		if len(accessToken) <= 0 {
			ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s not found", sysModel.TokenHeader)))
			c.Abort()
			return
		}
		t, err := r.s.AccessToken(accessToken)
		if err != nil {
			ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
			c.Abort()
			return
		}

		if t.Typ == 1 {
			r.admin(c, t, accessToken)
		} else {
			r.api(c, t, accessToken)
		}
	}
}
func (r *AdminRouter) api(c *gin.Context, token *token.Token, accessToken string) {
	user, err := r.s.ApiSessionUser(token, accessToken)
	if err != nil {
		ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
		c.Abort()
		return
	}
	if user.Id <= 0 {
		ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", "login out")))
		c.Abort()
		return
	}
	// 把数据写入到流中
	c.Set(sysModel.TokenHeader, user)
	c.Next()
}
func (r *AdminRouter) admin(c *gin.Context, token *token.Token, accessToken string) {
	//验证是否登录
	user, err := r.s.AdminSessionUser(token, accessToken)
	if err != nil {
		ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", err.Error())))
		c.Abort()
		return
	}
	if user.Id <= 0 {
		ginutil.RespErr(c, errc.ErrNeedLogin.MultiMsg(fmt.Sprintf("%s", "login out")))
		c.Abort()
		return
	}

	//权限的控制管理
	adminApi := c.Request.RequestURI
	if ok := UrlOk(adminApi); !ok {
		exist, err := r.s.UserActionExist(user, adminApi)
		if err != nil {
			ginutil.RespErr(c, errc.ErrAccessDenied.MultiMsg(fmt.Sprintf("%s", err.Error())))
			c.Abort()
			return
		}
		if !exist {
			ginutil.RespErr(c, errc.ErrAccessDenied.MultiMsg("access denied"))
			c.Abort()
			return
		}
	}

	//关于登录日志的处理
	var writer responseWriter
	optLog := &sysModel.SysOperateLog{}
	method := c.Request.Method
	if !(method == "GET" || method == "get") {
		requestBody := ""
		b, err := c.GetRawData()
		if err != nil {
			requestBody = "failed to get request body"
		} else {
			requestBody = string(b)
		}
		c.Request.Body = io.NopCloser(bytes.NewBuffer(b))
		writer = responseWriter{
			c.Writer,
			bytes.NewBuffer([]byte{}),
		}
		c.Writer = writer

		//记录的日志
		optLog.Path = c.Request.RequestURI
		optLog.RequestBody = requestBody
		optLog.Cost = time.Now().UnixMilli()
		optLog.Ip = c.ClientIP()
	}

	// 把数据写入到流中
	c.Set(sysModel.TokenHeader, user)

	c.Next()

	if !(method == "GET" || method == "get") {
		optLog.ResponseStatus = c.Writer.Status()
		optLog.ResponseBody = writer.b.String()
		optLog.Cost = time.Now().UnixMilli() - optLog.Cost
		title, _ := r.s.ActionWithTitle(optLog.Path)
		optLog.Opt = title
		optLog.UserId = user.Id
		optLog.UserName = user.UserName
		_ = r.s.OperateInsert(optLog)
	}
}

type MyLogs struct {
	Start          int64  `json:"start"`
	Path           string `json:"path"`           //请求接口路由
	RequestBody    string `json:"requestBody"`    //请求参数
	Ip             string `json:"ip"`             //请求参数
	ResponseBody   string `json:"responseBody"`   //请求参数
	ResponseStatus int    `json:"responseStatus"` //请求参数
	Cost           int64  `json:"cost"`           //耗时
}

// 自定义一个结构体，实现 gin.ResponseWriter interface
type responseWriter struct {
	gin.ResponseWriter
	b *bytes.Buffer
}

// 重写 Write([]byte) (int, error) 方法
func (w responseWriter) Write(b []byte) (int, error) {
	//向一个bytes.buffer中写一份数据来为获取body使用
	w.b.Write(b)
	//完成gin.Context.Writer.Write()原有功能
	return w.ResponseWriter.Write(b)
}
